﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Wen.Core
{
	public static class NavigatorHelpers
	{
		public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject reference, Func<T, bool> condition)
		where T : Model3D {
			if (reference != null) {
				if (reference is Model3DGroup)
				{
					foreach (Model3D model3D in ((Model3DGroup)reference).Children)
					{
						if (model3D is T)
							yield return (T) model3D;
						IEnumerable<T> findVisualChildren = model3D.FindVisualChildren<T>(condition);
						foreach (var matchingChild in findVisualChildren) {
							yield return matchingChild;
						}
					}
				}
				if (reference is Visual3D || reference is Visual) {
					int count = VisualTreeHelper.GetChildrenCount(reference);
					for (int i = 0; i < count; ++i) {
						DependencyObject child = VisualTreeHelper.GetChild(reference, i);
						T t = child as T;
						if (t != null && (condition == null || condition(t)))
							yield return t;
						ModelVisual3D modelVisual3D = child as ModelVisual3D;
						if (modelVisual3D != null) {
							if (modelVisual3D.Content is T)
								yield return (T)modelVisual3D.Content;
							IEnumerable<T> findVisualChildren = modelVisual3D.Content.FindVisualChildren<T>(condition);
							foreach (var matchingChild in findVisualChildren) {
								yield return matchingChild;
							}
						}
						foreach (T tt in child.FindVisualChildren(condition))
							yield return tt;
					}
				}
			}
		}

		public static IEnumerable<T> FindVisualChild<T>(this DependencyObject reference, Func<T, bool> condition)
		where T : FrameworkElement {
			if (reference == null)
				throw new ArgumentNullException("reference");
			int count = VisualTreeHelper.GetChildrenCount(reference);
			for (int i = 0; i < count; ++i) {
				DependencyObject child = VisualTreeHelper.GetChild(reference, i);
				T t = child as T;
				if (t != null && (condition == null || condition(t)))
					yield return t;
				foreach (T tt in child.FindVisualChild(condition))
					yield return tt;
			}
		}

		public static ResourceDictionary LoadResourceDictionary(string relativeUri) {
			relativeUri = "pack://application:,,," + relativeUri;
			Uri uri = new Uri(relativeUri, UriKind.Absolute);
			return new ResourceDictionary() { Source = uri };
		}

		public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
			HashSet<TKey> knownKeys = new HashSet<TKey>();
			foreach (TSource element in source) {
				if (knownKeys.Add(keySelector(element))) {
					yield return element;
				}
			}
		}
	}
}
